<?php
/**
 * Created by PhpStorm.
 * User: Yieong
 * Date: 14/11/24
 * Time: 下午4:42
 */


class PubAuth {

    /**
     * 标准校验入口
     * @param array $config         APP基础配置
     * @param bool $checkLogin      是否校验登陆
     * @param bool $checkMenu       是否校验菜单
     * @return bool
     */
    public static function run(array $config=null, $checkLogin=true, $checkMenu=true){
        // 后台脚本不进行任何验证
        if(PHP_SAPI === 'cli') return true;

        // 初始化配置
        PubAuthConfig::init($config);

        // 检查登陆
        if($checkLogin && !self::checkLogin()){
            if((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == strtolower('XMLHttpRequest')) || !empty($_REQUEST['isAjax'])){
                // 异步处理
            	$json_arr = array('status' => 0, 'msg' => '没有登陆','data'=>'');
            	exit(json_encode($json_arr));
                //PubAuthUtil::message('没有登陆');
            }else{
                // 非异步处理
                PubAuthUtil::goLogin();
            }
        }

        //对当前页面进行权限校验，没有权限则提示没有权限
        if ($checkMenu && !self::checkUrl()) {
        	if(PubFunc::isAjax()){
        		// 异步处理
        		$json_arr = array('status' => 0, 'msg' => '没有权限','data'=>'');
        		exit(json_encode($json_arr));
        	}else{
        		return false;
        		//PubAuthUtil::message('没有权限');
        	}
            
        }
        return true;
    }

    /**
     * 检测用户是否登陆
     * @return bool
     */
    public static function checkLogin(){
        if(PHP_SAPI === 'cli') return true;

        // 设置session超时时间
        if(PubAuthConfig::$SESSION_TIMEOUT > 0){
            $currentTime = time();
            $accTimeOut = PubAuthSession::get('acc_timeout');
            if(!empty($accTimeOut) && ($currentTime - $accTimeOut > PubAuthConfig::$SESSION_TIMEOUT)){
                PubAuthSession::destroy();
                PubAuthUtil::redirect("/home/?r=site/logout");
            }else{
                PubAuthSession::set('acc_timeout', $currentTime);
            }
        }

        $user = PubAuthSession::get('user');

        // 如果未登录系统
        if(!empty($user)){
            return true;
        }else{
            return false;
        }
    }

    public static function logout(){
        PubAuthSession::destroy();
        PubAuthUtil::redirect('/');
    }

    public static function getUser(){
        return PubAuthSession::get('user');
    }

    public static function setUser($arr){
        return PubAuthSession::set('user', $arr);
    }

    /**
     * 检测用户是否有URL权限
     * @param null $url
     * @return bool
     */
    public static function checkUrl($url = null, $appId = false){
        if(PHP_SAPI === 'cli') return true;

        // 如果用户是该系统的管理员，则获取所有权限
        $user = PubAuthSession::get('user');

        if($user['IsAdmin'] == 1){
            return true;
        }

        // 解析URL
        if(empty($url)) $url = $_SERVER['REQUEST_URI'];
        $params = PubAuthUtil::parseUrl($url);


        // 默认参数补充
        if(!empty(PubAuthConfig::$DEFAULT_PARAMS) && is_array(PubAuthConfig::$DEFAULT_PARAMS)){
            foreach(PubAuthConfig::$DEFAULT_PARAMS as $k=>$v){
                if(empty($params['Query'][$k])){
                    $params['Query'][$k] = $v;
                }
            }
        }

        // 获取用户在当前APP下的菜单
        $game = PubBase::getCurrentGame();
        $menu = self::getMenu($game);
        $function = array_merge($menu['Function'], PubAuthConfig::$NORMAL_URL);

        if(empty($function)){
            return false;
        }else{
            $isMatched = false;

            foreach($function as $v){
                $authParams = PubAuthUtil::parseUrl($v);

                // 校验域名Domain
                if ($authParams['Domain'] !== $params['Domain']) continue;

                // 校验目录路径Path
                if ($authParams['Path'] !== $params['Path']) continue;

                // 校验参数Query
                if(!empty($params['Query'])){
                    if (empty($authParams['Query'])) continue;

                    $customMap = array();

                    $isBreak = false;
                    foreach($authParams['Query'] as $kk=>$vv){

                        // 如果当前URL没有某个参数，无权限
                        if(!isset($params['Query'][$kk])) {
                            $isBreak = true;
                            break;
                        }else{
                            if(in_array($vv, PubAuthConfig::$APP_CUSTOM_MAP)){
                                $customMap[$vv] = $params['Query'][$kk];
                                continue;
                            }else if($params['Query'][$kk] !== $vv){
                                $isBreak = true;
                                break;
                            }
                        }
                    }

                    if (!$isBreak) {
                        if(!empty($customMap)){

                            $unsetPlatform = $unsetGame = false;
                            if(!empty($customMap['{$p}']) && self::getStateByPlatform($customMap['{$p}'])) $unsetGame = true;
                            if(!empty($customMap['{$g}']) && self::getStateByGame($customMap['{$g}'])) $unsetPlatform = true;

                            if($unsetPlatform && $unsetGame){
                                $isMatched = true;
                                break;
                            }else if($unsetPlatform){
                                unset($customMap['{$p}']);
                            }else if($unsetGame){
                                unset($customMap['{$g}']);
                            }

                            $game = self::getGame();

                            if(isset($customMap['{$g}']) && isset($customMap['{$p}'])){
                                $gameId = $game['Game'][$customMap['{$g}']]['GameID'];
                                if(isset($game['Details'][$customMap['{$p}'].'-'.$gameId])){
                                    $isMatched = true;
                                    break;
                                }
                            }else if(isset($customMap['{$g}'])){
                                if(isset($game['Game'][$customMap['{$g}']])){
                                    $isMatched = true;
                                    break;
                                }
                            }else if(isset($customMap['{$p}'])){
                                if(isset($game['Platform'][$customMap['{$p}']])){
                                    $isMatched = true;
                                    break;
                                }
                            }
                        }else{
                            $isMatched = true;
                            break;
                        }
                    }
                }else{
                    $isMatched = true;
                    break;
                }
            }

            return $isMatched;
        }

    }

    /**
     * 自动登录另一个地方的ACC地址
     * @param $domain 跳转免登的域名  eg:http://data.r2games.com/
     */
    public static function autoLogin($domain){
        $user = PubAuthSession::get('user');

        if(empty($user)) {
            PubAuthUtil::redirect($domain);
        }else{
            $time = time();
            $query = array(
                '__acc_action'  => 'autoLogin',
                'account'       => $user['Account'],
                'time'          => $time,
                'sign'          => md5($user['Account'] . PubAuthConfig::$ACC_LOGIN_KEY . $time)
            );

            $href = $domain . '?' . http_build_query($query);
            PubAuthUtil::redirect($href);
        }
    }

    /**
     * 获得当前APP下的菜单信息
     * @return array|null
     */
    public static function getMenu($gameSrc, $platformSrc=''){
        $user = PubAuthSession::get('user');

        $menuKey = "{$gameSrc}-menu";
        $menu = PubAuthSession::get($menuKey);

        if(!isset($menu) || $menu === false){
            $menu = PubAuthUtil::call('menu', array('userid' => $user['UserID'], 'game' => $gameSrc));
            PubAuthSession::set($menuKey, $menu);
        }

        return $menu;
    }

    /**
     * 获得当前用户的游戏信息
     * @return array|null
     */
    public static function getGame(){
        $user = PubAuthSession::get('user');

        $gameKey = 'game';
        $game = PubAuthSession::get($gameKey);
        if(!isset($game) || $game === false){
            $game = PubAuthUtil::call('game', array('userid' => $user['UserID']));
            PubAuthSession::set($gameKey, $game);
        }

        return $game;
    }

    public static function getMyGameList(){
        $game = self::getGame();
        return $game['Game'];
    }

    public static function getMyPlatformList(){
        $game = self::getGame();
        return $game['Platform'];
    }

    public static function getApp(){
        $user = PubAuthSession::get('user');

        $appKey = 'app';
        $app = PubAuthSession::get($appKey);

        if(!isset($app) || $app === false){
            $app = $user['App'];
            $appHasMenu = PubAuthUtil::call('app', array('userid' => $user['UserID']));

            if(!empty($app)){
                foreach($app as $k=>$v){
                    if(!isset($appHasMenu[$k]) && !in_array($v['UserType'], array('SA', 'DV'))){
                        unset($app[$k]);
                    }
                }
            }

//            $app = array();
//            foreach($tmp as $v){
//                $app[$v['AppCode']] = $v;
//            }

            PubAuthSession::set($appKey, $app);
        }

        return $app;
    }

    public static function addUser($staffId, $account, $userName, $email){
        $params = array(
            'StaffID'   => $staffId,
            'Account'   => $account,
            'UserName'  => $userName,
            'Email'     => $email
        );

        return PubAuthUtil::call('user::add', $params);
    }

    public static function getAllGame(){
        return PubAuthUtil::call('game::all');
    }

    public static function listUser(){
        return PubAuthUtil::call('user::all');
    }

    public static function getStateByPlatform($platform = false){
        $user = PubAuthSession::get('user');

        $key  = 'StateByPlatform';
        $list = PubAuthSession::get($key);

        if(!isset($list) || $list === false){
            $list = PubAuthUtil::call('game::getStateByPlatform', array('userid' => $user['UserID']));
            PubAuthSession::set($key, $list);
        }

        if($platform){
            return isset($list[$platform]) ? $list[$platform] : false;
        }else{
            return $list;
        }
    }

    public static function getStateByGame($game = false){
        $user = PubAuthSession::get('user');

        $key  = 'StateByGame';
        $list = PubAuthSession::get($key);

        if(!isset($list) || $list === false){
            $list = PubAuthUtil::call('game::getStateByGame', array('userid' => $user['UserID']));
            PubAuthSession::set($key, $list);
        }

        if($game){
            return isset($list[$game]) ? $list[$game] : false;
        }else{
            return $list;
        }
    }

    public static function getFavorite(){
        $key  = 'Favorite';
        $list = PubAuthSession::get($key);

        if(!isset($list) || $list === false){
            $user = PubAuthSession::get('user');

            $list = PubAuthUtil::call('favorite::get', array('id' => $user['UserID']));

            PubAuthSession::set($key, $list);
        }

        return $list;
    }

    public static function setFavorite($menuId){
        $user = PubAuthSession::get('user');
        $result = PubAuthUtil::call('favorite::set', array('id' => $user['UserID'], 'menu' => $menuId));

        if(!empty($result['state']) && $result['state']){
            $key  = 'Favorite';
            $list = self::getFavorite($key);

            if($result['type'] == 'add'){
                $list[$menuId] = $menuId;
            }else if($result['type'] == 'del'){
                unset($list[$menuId]);
            }

            PubAuthSession::set($key, $list);

            return true;
        }else{
            return false;
        }

    }

    public static function checkMenu($menuId){
        $user = PubAuthSession::get('user');
        $result = PubAuthUtil::call('user::check', array('id' => $user['UserID'], 'menu' => $menuId));
        return $result;
    }
}

class PubAuthClient {
    /**
     * 供ACC服务端调用的登陆接口
     */
    public static function accLogin(){
        $time   = PubAuthUtil::R('time');
        $userId = PubAuthUtil::R('userid');
        $sign   = PubAuthUtil::R('sign');
        $lang   = PubAuthUtil::R('lang');

        if(!empty($lang)) setcookie('language', $lang, 0, '/');

        if(time() - $time > PubAuthConfig::$APP_TIMEOUT) {
            PubAuthUtil::message('登陆超时，请重新登陆');
        }else if(!PubAuthUtil::call('check')){
            //检测ACC是否登陆
            PUbAccUtil::redirect('/home/?r=site/index');
        }else if(md5($userId . PubAuthConfig::$APP_KEY . $time) === $sign){
            self::loginByUser(array('id'=>$userId));
        }else{
            PubAuthUtil::message('与ACC校验失败');
        }
    }

    /**
     * 刷新权限
     */
    public static function refresh(){
        $user = PubAuthSession::get('user');

        if(empty($user['UserID'])){
            echo '没有登录';
            die;
        }else{
            PubAuthSession::destroy();
            self::loginByUser(array('id'=>$user['UserID']));
        }

    }

    /**
     * 供ACC服务端调用的退出接口
     */
    public static function accLogout(){
        PubAuthSession::destroy();
        exit();
    }

    /**
     * 内外网ACC自动登录接口
     */
    public static function autoLogin(){
        $time    = PubAuthUtil::R('time');
        $account = PubAuthUtil::R('account');
        $sign    = PubAuthUtil::R('sign');

        if(time() - $time > PubAuthConfig::$APP_TIMEOUT) {
            PubAuthUtil::message('登陆超时，请重新登陆');
        }else if(md5($account . PubAuthConfig::$ACC_LOGIN_KEY . $time) === $sign){
            self::loginByUser(array('account' => $account));
        }else{
            PubAuthUtil::message('与ACC校验失败');
        }
    }

    private static function loginByUser($arr){
        //获取个人信息
        $userInfo = PubAuthUtil::call('user', $arr);

        if(empty($userInfo)){
            PubAuthUtil::message('获取数据失败,请刷新!');
        }

        PubAuthSession::set('user', $userInfo);
        PubAuthSession::set('acc_timeout', time());

        $referer = PubAuthUtil::cookie('get', PubAuthConfig::$APP_REFERER);
        if(empty($referer)) {
            $referer = PubAuthConfig::$APP_URL;
        }
        PubAuthUtil::redirect($referer);
    }
}

class PubAuthConfig{
    public static $SESSION_PREFIX   = 'ACC_SESSION';            // Session前缀
    public static $APP_REFERER      = 'APP_REFERER';            // 保存回调URL的cookie名称
    public static $APP_TIMEOUT      = 300;
    public static $SESSION_TIMEOUT  = 0;
    public static $LOG_FILE         = '';

    public static $APP_URL_DOMAIN   = 'www.oa.com';
    public static $API_URL          = '/home/?r=api/index';
    public static $APP_CUSTOM_MAP   = array('{$g}','{$p}');

    public static $APP_SESSION_MEM_IP   = '127.0.0.1';
    public static $APP_SESSION_MEM_PORT = '11211';

    public static $NORMAL_URL = array();
    public static $DEFAULT_PARAMS = array();

    public static function init(array $config=null){
        if(!empty($config['APP_URL_DOMAIN']))
            self::$APP_URL_DOMAIN       = $config['APP_URL_DOMAIN'];
        if(!empty($config['APP_SESSION_MEM_IP']))
            self::$APP_SESSION_MEM_IP   = $config['APP_SESSION_MEM_IP'];
        if(!empty($config['APP_SESSION_MEM_PORT']))
            self::$APP_SESSION_MEM_PORT = $config['APP_SESSION_MEM_PORT'];
        if(!empty($config['SESSION_TIMEOUT']))
            self::$SESSION_TIMEOUT      = $config['SESSION_TIMEOUT'];
        if(!empty($config['NORMAL_URL']))
            self::$NORMAL_URL           = $config['NORMAL_URL'];
        if(!empty($config['DEFAULT_PARAMS']))
            self::$DEFAULT_PARAMS       = $config['DEFAULT_PARAMS'];
    }
}

class PubAuthUtil{

    /**
     * 进行登陆操作
     */
    public static function goLogin(){
        $referer = (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https').'://'
            .$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        PubAuthUtil::cookie('set', PubAuthConfig::$APP_REFERER, $referer);

        PubAuthUtil::redirect('/home/?r=site/index');
    }

    /**
     * 读取参数
     * @param $name             读取的Key值
     * @param array $request    如果传入数组，则从数组读取参数，否则从GET、Post读取
     * @return null
     */
    public static function R($name, array $request=NULL) {
        if ($request === NULL) {
            $_data = isset($_POST[$name]) ? $_POST[$name] : (isset($_GET[$name]) ? $_GET[$name] : NULL);
        } else {
            $_data = isset($request[$name]) ? $request[$name] : NULL;
        }

        return $_data;
    }

    /**
     * 调用ACC的API方法
     * @param $methods          调用方法多个方法用逗号分隔
     * @param array $data       传给方法的参数
     * @return array
     */
    public static function call($methods, array $params=array()){
        $methods = explode(',', $methods);

        $result = array();
        $cnt    = count($methods);

        // 遍历方法获取数据
        foreach($methods as $v){
            $_m = trim($v);

            if(strpos($_m, '::') > 0){
                list($_c, $_a) = explode('::', $_m);
            }else{
                $_c = $_m;
                $_a = 'get';
            }

            $tmp = call_user_func(array('Api'.(ucfirst($_c)), $_a), $params);

            if($cnt > 1){
                $result[$_m] = $tmp;
            }else{
                $result = $tmp;
            }
        }

        return $result;
    }

    /**
     * 发起CURL请求
     * @param $url              请求的地址
     * @param array $argument   参数
     * @param int $ttl          超时时间
     * @return array
     */
    public static function request($url, $argument=array(), $ttl=30) {
        if (empty($url)||
            (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0))
            return array('code'=>400, 'result'=>NULL);

        $header = array(
            'Accept-Language: zh-cn',
            'Connection: Keep-Alive',
            'Cache-Control: no-cache'
        );

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);

        if (!empty($argument)) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $argument);
        }

        if (strpos($url, 'https://') !== false) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }

        curl_setopt_array($ch, array(
            CURLOPT_RETURNTRANSFER  =>true,
            CURLOPT_CONNECTTIMEOUT  =>$ttl,
            CURLOPT_TIMEOUT         =>$ttl,
            CURLOPT_USERAGENT       =>"AUC API REQUEST(CURL) ",
            CURLOPT_HTTPHEADER      =>$header
        ));

        $return = array(
            'result'    =>curl_exec($ch),
            'code'      =>curl_getinfo($ch, CURLINFO_HTTP_CODE)
        );
        curl_close($ch);

        return $return;
    }

    /**
     * 跳转URL
     * @param $url
     * @param bool $message
     */
    public static function redirect($url, $message=false){
        header("Location:{$url}");
        exit;
    }

    /**
     * 展示信息
     * @param $text
     */
    public static function message($text){
        echo '<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>'. $text. '</body></html>';
        exit;
    }

    /**
     * 设置cookie的方法
     * @param $action       操作类型：get || set
     * @param $key          Key值
     * @param null $data    set时必须，value值
     * @return string
     */
    public static function cookie($action, $key, $value=NULL) {
        $path = '/';

        if ($action == 'set') {
            $value = urlencode($value);
            setcookie($key, $value, 0, $path);
        }
        elseif ($action == 'get') {
            $value = self::R($key, $_COOKIE);
            setcookie($key, '', time() - 3600, $path);
            return urldecode($value);
        }
    }

    /**
     * 解析URL
     * @param $url      传入的URL
     * @return array
     *      Domain  域名
     *      Path    目录路径
     *      Query   查询参数
     */
    public static function parseUrl($url){
        // 如果不是完整的地址
        if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) {
            $domain = PubAuthConfig::$APP_URL_DOMAIN;
            if ($domain !== $_SERVER['SERVER_NAME'] && !empty($_SERVER['SERVER_NAME'])) {
                $domain = $_SERVER['SERVER_NAME'];
            }

            list($_path, $_query) = explode('?', $url, 2);
            $path = trim($_path, '/');

            // 如果是完整的地址
        } else {
            $arr = parse_url($url);

            $domain     = $arr['host'];
            $path       = trim($arr['path'], '/');
            $_query     = $arr['query'];
        }

        $query = $_GET;
        if (!empty($_query)) {
            parse_str($_query, $query);
        }

//        $query = array_map('strtolower', $query);
        return array(
            'Domain' => strtolower($domain),
            'Path'   => strtolower($path),
            'Query'  => $query
        );
    }

    // 记录日志
    public static function log($msg){
        if(empty($msg) || empty(PubAuthConfig::$LOG_FILE)) return false;

        $time = date('Y-m-d H:i:s');

        file_put_contents(PubAuthConfig::$LOG_FILE, "\r\n--------------------------------\r\n\r\n", FILE_APPEND);
        file_put_contents(PubAuthConfig::$LOG_FILE, "[{$time}]", FILE_APPEND);
        file_put_contents(PubAuthConfig::$LOG_FILE, $msg, FILE_APPEND);
    }
}

class PubAuthSession {

    public static function start(){
        if(!isset($_SESSION)){
            session_start();
        }
    }

    public static function getKey($key){
        return PubAuthConfig::$SESSION_PREFIX . '_' . $key;
    }

    public static function get($key){
        self::start();
        $key = self::getKey($key);
        return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
    }

    public static function set($key, $value){
        self::start();
        $key = self::getKey($key);
        $_SESSION[$key] = $value;
        return true;
    }

    public static function destroy(){
        self::start();

        // 重置会话中的所有变量
        $_SESSION = array();

        // 如果要清理的更彻底，那么同时删除会话 cookie
        // 注意：这样不但销毁了会话中的数据，还同时销毁了会话本身
        if (ini_get("session.use_cookies")) {
            $params = session_get_cookie_params();
            setcookie(session_name(), '', time() - 42000,
                $params["path"], $params["domain"],
                $params["secure"], $params["httponly"]
            );
        }

        session_destroy();
    }

}